<template>
	<view class="model" :thumb="options" :change:thumb="renderScript.update">
		<block v-if="thumb">
			<view id="d3Container" ref="mainContent"></view>
			<view class="loading" v-if="loading">
				<u-loading-icon></u-loading-icon>
				<text>{{schedule}}%</text>
			</view>
		</block>
		<block v-else>
			<view class="loading" >
				<u-loading-icon></u-loading-icon>
				<text>loading...</text>
			</view>
		</block>
	</view>
</template>
<!-- #ifdef H5 -->
<script>
	import * as THREE from 'three'
	import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
	import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
	export default {
		props:{
			type:{
				type:Number,
				default:1,
			},
			thumb:{
				type:String,
				default:'',
			},
			model:{
				type:String,
				// default:'http://192.168.50.107:18082/download/132.glb',
				default:()=>{
					return ''
				},
				// default:'/api/132.glb',
			}
		},
		data() {
			return {
				cWidth:0,
				cHeight:0,
				schedule:0,
				loading: false,
				mesh: null,
				camera: null,
				scene: null,
				originX: -2,
				originY: 0,
				originZ: 9,
				renderer: null,
				controls: null,
				ob:null,
				options:{},
			}
		},
		mounted() {
			
		},
		methods: {
			// 初始化
			init() {
			    this.createScene() // 创建场景
			    this.loadLoader() // 加载P模型
			    this.createLight() // 创建光源
			    this.createCamera() // 创建相机
			    this.createRender() // 创建渲染器
			    this.createControls() // 创建控件对象
			    this.render() // 渲染
			},
			//清除当前所有场景
			clear() {
				this.mesh = null
				this.camera = null
				this.scene = null
				this.renderer = null
				this.controls = null
				this.ob = null
				cancelAnimationFrame(this.animationId)
				// console.log("我要清除啦");
			},
			// 创建场景
			createScene() {
			    this.loading = true;
			    this.scene = new THREE.Scene()
				
				// var grid = new THREE.GridHelper(24, 24, 0xFF0000, 0x444444);
				// grid.material.opacity = 0.4;
				// grid.material.transparent = true;
				// grid.rotation.x = Math.PI / 2.0;
				// this.scene.add(grid)
			},
			// 加载模型
			loadLoader() {
			    const THIS = this
				const url = 'https://api.zyrnft.cn/index/o/backimg2.png'
				this.ob = new THREE.Object3D() // 创建一个ob类
				if(this.type==1){
					var textureLoader = new THREE.TextureLoader() ;
					// 定义物体的几何结构
					var sphereGeometry = new THREE.BoxBufferGeometry(5,5,0.2);
					// 定义物体的材质
					var sphereMaterial = [
						//下标0：右面材质
						new THREE.MeshBasicMaterial({
						    color: '#222423',
						    // wireframe: true,
							opacity:0,
							transparent:true
						}),
						//下标1：左面材质
						new THREE.MeshBasicMaterial({
						    color: '#222423',
						    wireframe: true,
							opacity:0,
							transparent:true
						}),
						//下标2：上面材质
						new THREE.MeshBasicMaterial({
						    color: '#222423',
						    wireframe: true,
							opacity:0,
							transparent:true
						}),
						//下标3：下面材质
						new THREE.MeshBasicMaterial({
						    color: '#222423',
						    wireframe: true,
							opacity:0,
							transparent:true
						}),
						//下标4：前面材质
						new THREE.MeshBasicMaterial({
						    map: textureLoader.load(this.thumb)
						}),
						//下标5：后面材质
						new THREE.MeshBasicMaterial({
						    // map: textureLoader.load(this.$api.backimg)
						    map: textureLoader.load(url)
						}),
					]
					// 用刚才定义的几何结构和材质来创建物体
					let sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
					this.ob.add(sphere)
				}
				const manager = new THREE.LoadingManager();
				manager.onProgress = ( item, loaded, total )=> {
					// console.log( '[进度]',(loaded / total * 100 ) + '% loaded' );
					this.schedule = loaded / total * 100 
				};
				let loader = new GLTFLoader(manager);
			    loader.load(this.model, geometry => {
					// console.log('[模型]',geometry)
			        // loader.load(THIS.ossPath, geometry => {
			        //   geometry.center();
			        this.loading = false;
			        let material = null;
			        // this.isLoading = false;//关闭载入中效果
			        this.mesh = geometry.scene;
					
					// let box = new THREE.Box3().setFromObject(this.mesh);
			        
			        if(this.type==2){
						this.mesh.traverse((object)=>{
						    if(object.isMesh){
						        object.castShadow = true;                     
						    }
						});
						this.mesh.scale.set(1,1,1);   
						                
						let group = new THREE.Group();
						group.add(this.mesh);
						
						let bbox = new THREE.Box3().setFromObject(group);
						let mdlen=bbox.max.x-bbox.min.x; //边界的最小坐标值 边界的最大坐标值
						let mdhei=bbox.max.y-bbox.min.y; 
						let mdwid=bbox.max.z-bbox.min.z;
						group.position.set(0,0,0); 
						// console.log('[------------]',bbox,mdlen,mdhei,mdwid);
						// 计算相机到物体正面的距离。
						let dist =Math.abs(this.camera.position.z - group.position.z- (mdwid/2));
						// console.log('[------------]',this.camera.position.z,group.position.z,mdwid/2);
						// console.log('dist值为:' + dist );
						// 将垂直fov转换为弧度
						let vFov = this.camera.fov * Math.PI/180;
						// console.log('vFov值为:',vFov,this.camera );
						// 可见高度
						let vheight = 1.8 * Math.tan(vFov * 0.5) *dist;
						// console.log('vheight值为:' + vheight );
						// 可见高度的分数
						let fraction = mdhei / vheight;
						// console.log('fraction值为:' + fraction );
						// 立方体的高度(以像素为单位)是画布的高度(以像素为单位)的fraction倍。
						let finalHeight = this.cHeight * fraction ;                
						// console.log('finalHeight值为:' + finalHeight);
						// 包围盒计算的高/finalHeight = 包围盒计算的宽/finalWidth
						let finalWidth = (finalHeight*mdlen) /mdhei;             
						// console.log('finalWidth值为:' + finalWidth );                
						
						let value1 = (this.cWidth-150)/finalWidth;
						// console.log('value1缩放比例值为:' + value1);
						let value2 = (this.cHeight-150)/finalHeight;
						// console.log('value2缩放比例值为:' + value2);
						
						if(value1 >= value2){
						    group.scale.set(value2,value2,value2);
						}
						else{
						    group.scale.set(value1,value1,value1);
						} 
						let bbox2= new THREE.Box3().setFromObject(group)
						let mdlen2=bbox2.max.x-bbox2.min.x;
						let mdhei2=bbox2.max.y-bbox2.min.y;
						let mdwid2=bbox2.max.z-bbox2.min.z;
						group.position.set(-(bbox2.max.x+bbox2.min.x)/2,-(bbox2.max.y+bbox2.min.y)/2,-(bbox2.max.z+bbox2.min.z)/2);
						
						// this.scene.add(group);
						this.ob.add(group)                
						// let boxhelper = new THREE.BoxHelper(group,0xbe1915); //外面红色框
						// this.scene.add(boxhelper);
						// this.ob.add(boxhelper)    
					}
					if(this.type==1){
						this.mesh.position.set(0, 0, 0);//设置位置
						this.mesh.scale.set(1, 1, 2.5)//设置大小比例
						geometry.scene.children.forEach(item=>{
							item.material = new THREE.MeshStandardMaterial();                 
							item.material.color=new THREE.Color(0x999999);
							item.material.metalness = 0.44;
							item.material.roughness =0;
							item.material.transparent=true;
							item.material.opacity=0.4;
							item.material.envMap=textureLoader.load(this.thumb);
							//环境反射贴图envMap的映射方式，这里用的是一个叫等量矩形投影的映射方法
							item.material.envMap.mapping = THREE.EquirectangularReflectionMapping;
							//环境反射贴图的强度
							item.material.envMapIntensity=1;
						})
						
						this.ob.add(this.mesh)
						
					}
					this.scene.add(this.ob); // 将模型引入three、
			    })
			    //如果有配准结果,加载配准结果,配准结果未ply格式;
			},
			// 创建光源
			createLight() {
			    // 环境光
			    let pointColor = '#ffffff';
			    // const ambientLight = new THREE.AmbientLight(0x222222, 0.35) // 创建环境光
				const ambientLight = new THREE.AmbientLight(0x0c0c0c);
				// ambientLight.position.set(10, 10, 50);
			    this.scene.add(ambientLight) // 将环境光添加到场景
			    const spotLight = new THREE.DirectionalLight(0xdfebff, 1);
			    spotLight.position.set(50, 50, -50)
			    spotLight.castShadow = true;//平行光开启阴影
			    spotLight.receiveShadow = true;
			    this.scene.add(spotLight)
				const spotLight2 = new THREE.SpotLight(0xffffff) // 创建聚光灯
				spotLight2.position.set(50, 50, 50)
				spotLight2.castShadow = true;//平行光开启阴影
				spotLight2.receiveShadow = true;
				this.scene.add(spotLight2)
			},
			// 创建相机
			createCamera() {
				const element = document.getElementById("d3Container");
				const width = element.clientWidth // 窗口宽度
				const height = element.clientHeight //
				this.cWidth = width;
				this.cHeight = height;
				const k = width / height // 窗口宽高比
				this.aspect = k;
				// PerspectiveCamera( fov, aspect, near, far )
				if(this.type==2){
					this.camera = new THREE.PerspectiveCamera(45,this.cWidth/this.cHeight,0.1,1000);
				}
				if(this.type==1){
					this.camera = new THREE.PerspectiveCamera(50, k, 0.25, 10000)
				}
				this.camera.position.set(-2, 0,9) // 设置相机位置
				// this.camera.up.set(0, 0, 1);
				this.camera.lookAt(new THREE.Vector3(0, 1, 0)) // 设置相机方向
				this.scene.add(this.camera)
			},
			// 创建渲染器
			createRender() {
			    const element = document.getElementById("d3Container");
			    this.renderer = new THREE.WebGLRenderer({
					antialias: true, 
					alpha: true, 
					preserveDrawingBuffer: true,
				})
			    this.renderer.setSize(element.clientWidth, element.clientHeight) // 设置渲染区域尺寸
				this.renderer.setPixelRatio(window.devicePixelRatio)
			    this.renderer.shadowMap.enabled = true // 显示阴影
			    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap
			    // this.renderer.setClearColor(new THREE.Color(0xEEEEEE)) // 设置背景颜色
			    // this.renderer.setClearColor(new THREE.Color(0x111111)) // 设置背景颜色
			    element.innerHTML = '';
				// console.log('[渲染器]',element.appendChild)
			    element.appendChild(this.renderer.domElement)
			},
			render() {
				this.ob.rotateY(Math.PI/-720);
				this.animationId = requestAnimationFrame(this.render);//旋转动画;
				this.renderer.render(this.scene, this.camera)
				this.controls.update();
				
			},
			// 创建控件对象
			createControls() {
				this.controls = new OrbitControls(this.camera, this.renderer.domElement)
				// to disable zoom
				this.controls.enableZoom = true;
				
				// to disable rotation
				this.controls.enableRotate = true;
				
				// to disable pan
				this.controls.enablePan = true;
			},
			onWindowResize() {
				this.camera.aspect = this.aspect;
				this.camera.updateProjectionMatrix();
			}
		},
		destroyed() {
		    this.clear();
		},
		
		watch:{
			thumb(val){
				// console.log('[数据变更]',val)
				this.options = {
					thumb:val,
					type:this.type,
					backimg:this.$api.backimg,
					model:this.model
				}
			},
			// #ifndef MP-WEIXIN || APP
			model(val){
				// console.log('[变更]',val)
				if(val){
					// this.init()
				}
			}
			// #endif
		},
		 
	}
</script>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN || H5 -->
<script module="renderScript" lang="renderjs">
	import * as THREE from 'three'
	import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
	import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
	export default {
		data() {
			return {
				mesh: null,
				camera: null,
				scene: null,
				originX: -2,
				originY: 0,
				originZ: 9,
				renderer: null,
				controls: null,
				ob:null,
				options:{}
			}
		},
		mounted() {
			// this.init()
		},
		methods: {
			update(newValue, oldValue, ownerInstance, instance){
				// console.log('[model数据变更----------------]',this.options.model)
				// console.log('[thumb数据变更----------------]',this.options.thumb)
				this.options = newValue
				if(this.options.thumb||this.options.model){
					this.init()
				}
			},
			// 初始化
			init() {
			    this.createScene() // 创建场景
			    this.loadLoader() // 加载P模型
			    this.createLight() // 创建光源
			    this.createCamera() // 创建相机
			    this.createRender() // 创建渲染器
			    this.createControls() // 创建控件对象
			    this.render() // 渲染
			},
			//清除当前所有场景
			clear() {
				this.mesh = null
				this.camera = null
				this.scene = null
				this.renderer = null
				this.controls = null
				this.ob = null
				cancelAnimationFrame(this.animationId)
				console.log("我要清除啦");
			},
			// 创建场景
			createScene() {
			    this.loading = true;
			    this.scene = new THREE.Scene()
			    // var grid = new THREE.GridHelper(24, 24, 0xFF0000, 0x444444);
			    // grid.material.opacity = 0.4;
			    // grid.material.transparent = true;
			    // grid.rotation.x = Math.PI / 2.0;
			    // this.scene.add(grid)
			},
			// 加载模型
			loadLoader() {
			    const THIS = this
			    // const loader = this.mapLoader();
			    
				this.ob = new THREE.Object3D() // 创建一个ob类
				if(this.options.type==1){
					var textureLoader = new THREE.TextureLoader() ;
					// 定义物体的几何结构
					var sphereGeometry = new THREE.BoxBufferGeometry(5,5,0.2);
					// 定义物体的材质
					var sphereMaterial = [
						//下标0：右面材质
						new THREE.MeshBasicMaterial({
						    color: '#222423',
						    // wireframe: true,
							opacity:0,
							transparent:true
						}),
						//下标1：左面材质
						new THREE.MeshBasicMaterial({
						    color: '#222423',
						    wireframe: true,
							opacity:0,
							transparent:true
						}),
						//下标2：上面材质
						new THREE.MeshBasicMaterial({
						    color: '#222423',
						    wireframe: true,
							opacity:0,
							transparent:true
						}),
						//下标3：下面材质
						new THREE.MeshBasicMaterial({
						    color: '#222423',
						    wireframe: true,
							opacity:0,
							transparent:true
						}),
						//下标4：前面材质
						new THREE.MeshBasicMaterial({
						    map: textureLoader.load(this.options.thumb)
						}),
						//下标5：后面材质
						new THREE.MeshBasicMaterial({
						    map: textureLoader.load(this.options.backimg)
						}),
					]
					// 用刚才定义的几何结构和材质来创建物体
					let sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
					this.ob.add(sphere)
				}
				const manager = new THREE.LoadingManager();
				manager.onProgress = ( item, loaded, total )=> {
					// console.log( '[进度]',(loaded / total * 100 ) + '% loaded' );
					this.schedule = loaded / total * 100 
				};
				let loader = new GLTFLoader(manager);
				// console.log('[模型]',loader)
				
			    loader.load(this.options.model, geometry => {
					// console.log('[模型]',geometry)
			        // loader.load(THIS.ossPath, geometry => {
			        //   geometry.center();
			        this.loading = false;
			        let material = null;
			        // this.isLoading = false;//关闭载入中效果
			        this.mesh = geometry.scene;
					let box = new THREE.Box3().setFromObject(this.mesh);
			        if(this.options.type==2){
						this.mesh.traverse((object)=>{
						    if(object.isMesh){
						        object.castShadow = true;                     
						    }
						});
						this.mesh.scale.set(1,1,1);   
						                
						let group = new THREE.Group();
						group.add(this.mesh);
						
						let bbox = new THREE.Box3().setFromObject(group);
						let mdlen=bbox.max.x-bbox.min.x; //边界的最小坐标值 边界的最大坐标值
						let mdhei=bbox.max.y-bbox.min.y; 
						let mdwid=bbox.max.z-bbox.min.z;
						group.position.set(0,0,0); 
						// console.log('[------------]',bbox,mdlen,mdhei,mdwid);
						// 计算相机到物体正面的距离。
						let dist =Math.abs(this.camera.position.z - group.position.z- (mdwid/2));
						// console.log('[------------]',this.camera.position.z,group.position.z,mdwid/2);
						// console.log('dist值为:' + dist );
						// 将垂直fov转换为弧度
						let vFov = this.camera.fov * Math.PI/180;
						// console.log('vFov值为:',vFov,this.camera );
						// 可见高度
						let vheight = 1.8 * Math.tan(vFov * 0.5) *dist;
						// console.log('vheight值为:' + vheight );
						// 可见高度的分数
						let fraction = mdhei / vheight;
						// console.log('fraction值为:' + fraction );
						// 立方体的高度(以像素为单位)是画布的高度(以像素为单位)的fraction倍。
						let finalHeight = this.cHeight * fraction ;                
						// console.log('finalHeight值为:' + finalHeight);
						// 包围盒计算的高/finalHeight = 包围盒计算的宽/finalWidth
						let finalWidth = (finalHeight*mdlen) /mdhei;             
						// console.log('finalWidth值为:' + finalWidth );                
						
						let value1 = (this.cWidth-150)/finalWidth;
						// console.log('value1缩放比例值为:' + value1);
						let value2 = (this.cHeight-150)/finalHeight;
						// console.log('value2缩放比例值为:' + value2);
						
						if(value1 >= value2){
						    group.scale.set(value2,value2,value2);
						}
						else{
						    group.scale.set(value1,value1,value1);
						} 
						let bbox2= new THREE.Box3().setFromObject(group)
						let mdlen2=bbox2.max.x-bbox2.min.x;
						let mdhei2=bbox2.max.y-bbox2.min.y;
						let mdwid2=bbox2.max.z-bbox2.min.z;
						group.position.set(-(bbox2.max.x+bbox2.min.x)/2,-(bbox2.max.y+bbox2.min.y)/2,-(bbox2.max.z+bbox2.min.z)/2);
						
						// this.scene.add(group);
						this.ob.add(group)                
						// let boxhelper = new THREE.BoxHelper(group,0xbe1915); //外面红色框
						// this.scene.add(boxhelper);
						// this.ob.add(boxhelper)    
					}
					if(this.options.type==1){
						this.mesh.position.set(0, 0, 0);//设置位置
						this.mesh.scale.set(1, 1, 2.5)//设置大小比例
						geometry.scene.children.forEach(item=>{
							item.material = new THREE.MeshStandardMaterial();                 
							item.material.color=new THREE.Color(0x999999);
							item.material.metalness = 0.44;
							item.material.roughness =0;
							item.material.transparent=true;
							item.material.opacity=0.3;
							item.material.envMap=textureLoader.load(this.options.thumb);
							//环境反射贴图envMap的映射方式，这里用的是一个叫等量矩形投影的映射方法
							item.material.envMap.mapping = THREE.EquirectangularReflectionMapping;
							//环境反射贴图的强度
							item.material.envMapIntensity=1;
						})
						
						this.ob.add(this.mesh)
					}
					// this.ob.add(this.mesh) 
			        this.scene.add(this.ob); // 将模型引入three、
			    })
				// this.ob.add(this.mesh)
				// this.scene.add(this.ob); // 将模型引入three、
			    //如果有配准结果,加载配准结果,配准结果未ply格式;
			},
			// 创建光源
			createLight() {
			    // 环境光
			    let pointColor = '#ffffff';
			    // const ambientLight = new THREE.AmbientLight(0x222222, 0.35) // 创建环境光
				const ambientLight = new THREE.DirectionalLight(0xffffff);
				ambientLight.position.set(10, 10, 50);
			    this.scene.add(ambientLight) // 将环境光添加到场景
			    const spotLight = new THREE.SpotLight(0xffffff) // 创建聚光灯
			    spotLight.position.set(50, -50, -50)
			    spotLight.castShadow = true;//平行光开启阴影
			    spotLight.receiveShadow = true;
			    this.scene.add(spotLight)
				const spotLight2 = new THREE.SpotLight(0xffffff) // 创建聚光灯
				spotLight2.position.set(50, -50, 50)
				spotLight2.castShadow = true;//平行光开启阴影
				spotLight2.receiveShadow = true;
				this.scene.add(spotLight2)
			},
			// 创建相机
			createCamera() {
				const element = document.getElementById("d3Container");
				const width = element.clientWidth // 窗口宽度
				const height = element.clientHeight //
				this.cWidth = width;
				this.cHeight = height;
				const k = width / height // 窗口宽高比
				this.aspect = k;
				// PerspectiveCamera( fov, aspect, near, far )
				if(this.options.type==2){
					this.camera = new THREE.PerspectiveCamera(45,this.cWidth/this.cHeight,0.1,1000);
				}
				if(this.options.type==1){
					this.camera = new THREE.PerspectiveCamera(50, k, 0.25, 10000)
				}
				this.camera.position.set(-2, 0,9) // 设置相机位置
				// this.camera.up.set(0, 0, 1);
				this.camera.lookAt(new THREE.Vector3(0, 1, 0)) // 设置相机方向
				this.scene.add(this.camera)
			},
			// 创建渲染器
			createRender() {
			    const element = document.getElementById("d3Container");
			    this.renderer = new THREE.WebGLRenderer({
					antialias: true, 
					alpha: true, 
					preserveDrawingBuffer: true,
				})
			    this.renderer.setSize(element.clientWidth, element.clientHeight) // 设置渲染区域尺寸
				this.renderer.setPixelRatio(window.devicePixelRatio)
			    this.renderer.shadowMap.enabled = true // 显示阴影
			    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap
			    // this.renderer.setClearColor(new THREE.Color(0xEEEEEE)) // 设置背景颜色
			    // this.renderer.setClearColor(new THREE.Color(0x111111)) // 设置背景颜色
			    element.innerHTML = '';
				// console.log('[渲染器]',element.appendChild)
			    element.appendChild(this.renderer.domElement)
			},
			render() {
				this.ob.rotateY(Math.PI/-720);
				this.animationId = requestAnimationFrame(this.render);//旋转动画;
				this.renderer.render(this.scene, this.camera)
				this.controls.update();
			},
			// 创建控件对象
			createControls() {
				this.controls = new OrbitControls(this.camera, this.renderer.domElement)
				// to disable zoom
				this.controls.enableZoom = true;
				
				// to disable rotation
				this.controls.enableRotate = true;
				
				// to disable pan
				this.controls.enablePan = true;
			},
			onWindowResize() {
				this.camera.aspect = this.aspect;
				this.camera.updateProjectionMatrix();
			}
		},
		destroyed() {
		    this.clear();
		},
	};
</script>
<!-- #endif -->

<style lang="scss" scoped>
	.model {
		position: relative;
		#d3Container{
			width: 100%;
			height: 600rpx;
		}
		.loading{
			display: flex;
			flex-direction: column;
			justify-content: center;
			align-items: center;
			width: 100%;
			height: 600rpx;
			font-size: 24rpx;
		}
	}
</style>
